/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 * @file main.c
 * @author Nations Firmware Team
 * @version v1.0.1
 *
 * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 */

/** @addtogroup 
 * @{
 */
 
/* Includes ------------------------------------------------------------------*/
#include "n32wb03x.h"
#include "rwip.h"
#include "ns_ble.h"
#include "ns_sleep.h"
#include "ns_delay.h"
#include "ns_log.h"
#include "app_usart.h"
//#include "app_gpio.h"
#include "app_ble.h"
#include "spi.h"
#if  (CFG_APP_NS_IUS)
#include "ns_dfu_boot.h"
#endif

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DEMO_STRING  "\r\n Nations raw data transfer server(128bit UUID) demo \r\n"

/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

#include "spi.h"
#include "ctrl.h"
#include "display.h"
/**
 * @brief  main function
 * @param   
 * @return 
 * @note   Note
 */
 
#define KEY_NORMAL 0
#define KEY_CLICKED 1
#define KEY_LONG_CLICKED 2
#define KEY_LONG_LONG_CLICKED 3
#define KEY_LONG_CLICK_TIME (100000)
#define KEY_LONG_LONG_CLICK_TIME (200000)

uint32_t count_time  = 0;
uint32_t count_press_down_time = 0;
uint32_t press_flag  = KEY_NORMAL;

#define KEY_INPUT_PORT        GPIOB
#define KEY_INPUT_PIN         GPIO_PIN_10
#define KEY_INPUT_EXTI_LINE   EXTI_LINE5
#define KEY_INPUT_PORT_SOURCE GPIOB_PORT_SOURCE
#define KEY_INPUT_PIN_SOURCE  GPIO_PIN_SOURCE10
#define KEY_INPUT_IRQn        EXTI4_12_IRQn

extern void app_send_gapm_reset_cmd(void);

#define USE_ADC_16BIT_DMA   1
#define ADC_16BIT_DROP      8
#define ADC_DMA_BUF_SIZE    250
#define ADC_AVG_NUM         200

#if ((ADC_AVG_NUM+ADC_16BIT_DROP) > ADC_DMA_BUF_SIZE)
#error "ADC_AVG_NUM+ADC_16BIT_DROP must less than ADC_DMA_BUF_SIZE!!!"
#endif

extern void system_delay_n_10us(uint32_t value);

int16_t ADCBuf[ADC_DMA_BUF_SIZE];

void EXTI5_IRQHandler(void)
{
    //    static  uint8_t counti  = 0;
    if (RESET != EXTI_GetITStatus(KEY_INPUT_EXTI_LINE)) {
        delay_n_10us(100);
        printf("into io irq\r\n");
        if (GPIO_ReadInputDataBit(KEY_INPUT_PORT, KEY_INPUT_PIN) == RESET) {
            count_time = 8;
            count_press_down_time = 8;
            press_flag = KEY_CLICKED;
        } 
        delay_n_ms(100);

        EXTI_ClrITPendBit(KEY_INPUT_EXTI_LINE);
    }

    if (RESET != EXTI_GetITStatus(EXTI_LINE11)) {
        EXTI_ClrITPendBit(EXTI_LINE11);
    }
}

void KeyInputExtiInit(GPIO_Module* GPIOx, uint16_t Pin)
{
    GPIO_InitType GPIO_InitStructure;
    EXTI_InitType EXTI_InitStructure;
    NVIC_InitType NVIC_InitStructure;

    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

    /* Enable the GPIO Clock */
    if (GPIOx == GPIOA)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_AFIO, ENABLE);
    }
    else if (GPIOx == GPIOB)
    {
        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_AFIO, ENABLE);
    }
    else
    {
        return;
    }

    /*Configure the GPIO pin as input floating*/
    if (Pin <= GPIO_PIN_ALL)
    {
        GPIO_InitStruct(&GPIO_InitStructure);
        GPIO_InitStructure.Pin          = Pin;
        GPIO_InitStructure.GPIO_Pull    = GPIO_PULL_UP;//GPIO_NO_PULL;
        GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure);
    }

    /*Configure key EXTI Line to key input Pin*/
    GPIO_ConfigEXTILine(KEY_INPUT_PORT_SOURCE, KEY_INPUT_PIN_SOURCE);

    /*Configure key EXTI line*/
    EXTI_InitStructure.EXTI_Line    = KEY_INPUT_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // EXTI_Trigger_Rising_Falling; // EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitPeripheral(&EXTI_InitStructure);

    /*Set key input interrupt priority*/
    NVIC_InitStructure.NVIC_IRQChannel                   = KEY_INPUT_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority           = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
 
}
void PB12_init(void)
{
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_AFIO, ENABLE);

    GPIO_InitType GPIO_InitStructure;

    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pin          = GPIO_PIN_12;
    GPIO_InitStructure.GPIO_Pull    = GPIO_NO_PULL;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_PIN_12); 
}    

//void PB12_deinit(void)
//{
//    GPIO_ResetBits(GPIOB, GPIO_PIN_12); 
//    GPIO_InitType GPIO_InitStructure;
//    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);
//    GPIO_InitStruct(&GPIO_InitStructure);
//    GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_ANALOG;
//    GPIO_InitStructure.Pin          = GPIO_PIN_12;
//    GPIO_InitStructure.GPIO_Pull    = GPIO_NO_PULL;
//    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
//}    

void EXTI2_3_IRQHandler(void)
{
//    EXTI_ClrITPendBit(KEY_INPUT_EXTI_LINE);
    EXTI_ClrITPendBit(EXTI_LINE2);
    EXTI_ClrITPendBit(EXTI_LINE3);
    printf("222222222222223\r\n");
   
}    
void EXTI0_1_IRQHandler(void)
{
    EXTI_ClrITPendBit(EXTI_LINE0);
    EXTI_ClrITPendBit(EXTI_LINE1);

    printf("1111111111111110\r\n");
}  

uint8_t switch_swd(void)
{
    GPIO_InitType GPIO_InitStructure;

    GPIO_InitStruct(&GPIO_InitStructure);    

    /* Configure USARTx Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_5;
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF0;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);   

    /* Configure USARTx Rx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_4;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF0;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
    return 0;
}  


//void check_powerup_by_long_press(void)
//{
//    printf("%08x\r\n", REG32(USER_RESET_REG));
//    if(REG32(USER_RESET_REG) == USER_RESET_FLAG)
//    {
//        REG32(USER_RESET_REG) = 0xFFFFFFF;
//        switch_swd();
//    }
//    else //into sleep
//    {
//        REG32(USER_RESET_REG) = 0xFFFFFFF;
//        press_flag = 2;
//    }
//    
//}    
void set_flag_reset_work(void)
{
    REG32(USER_RESET_REG) = USER_RESET_WORK;
}   

void set_flag_reset_work_by_bt(void)
{
    REG32(USER_RESET_REG) = USER_RESET_WORK_BY_BT;
}

void set_flag_reset_sleep(void)
{
    REG32(USER_RESET_REG) = 0xFFFFFFFF;
}  

void sleep_check(void)
{
     if(REG32(USER_RESET_REG) == USER_RESET_WORK ||
        REG32(USER_RESET_REG) == USER_RESET_WORK_BY_BT)
     {
         printf("work\r\n");   
     }   
     else
     {    
         printf("sleep");
         __set_PRIMASK(1);               
         RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_PWR, ENABLE);
         PWR_EnterSLEEPMode(PWR_SLEEPENTRY_WFI);
         RCC->CFG |=  RCC_HCLK_DIV2; //APB1 = HCLK/2, APB1 max is 32M
         NS_LOG_INIT();
         printf("wakeup\r\n"); 
         set_flag_reset_work();
         NVIC_SystemReset();
     }     
}    

static uint16_t bat_vol1, bat_vol2, bat_vol3, bat_vol4;
static uint16_t ADC16bit_SingleRead_Val(uint16_t Channel , uint8_t avg_num)
{
    int32_t  sum = 0;
    uint16_t i,null_num;
    int16_t adc_val;
	/* Enable peripheral clocks */
    /* Enable ADC clocks */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE);
    RCC_ConfigAdcClk(RCC_ADCCLK_SRC_AUDIOPLL);
    /* enable ADC 4M clock */
    RCC_Enable_ADC_CLK_SRC_AUDIOPLL(ENABLE);
    /* configer ADC */
	ADC_EnableBypassFilter(ADC, DISABLE);
    ADC_ConfigContinuousMode(ADC, ENABLE);
    ADC_ConfigChannel(ADC, Channel);
    ADC_Enable(ADC, ENABLE);
    /* drop invalid data  */
    system_delay_n_10us(100); //1ms 
    /* get adc data  */
    null_num = 0;
    for(i = 0; i<avg_num; i++)
    {
        adc_val = ADC_GetDat(ADC);
        if(adc_val == 0)
        {
            // printf("err adc\r\n");
            null_num++;
            continue;
        }
        sum += adc_val;
        system_delay_n_10us(20);
    }
    ADC_Enable(ADC, DISABLE);
    adc_val = sum/(avg_num-null_num);
    return adc_val;
}

uint16_t ADC16Bit_GetOffsetAtVCC(void)
{
    uint16_t get_vol, adc_val;
    GPIO_SetBits(GPIOB, GPIO_PIN_12);
    adc_val = ADC16bit_SingleRead_Val(ADC_CTRL_CH_6, 20);
    get_vol = ADC16Bit_ConverValueToVoltage(adc_val, ADC_CTRL_CH_6, 0);
    printf("adc=%d,vol=%d\r\n", adc_val, get_vol);
    bat_vol4 = bat_vol3;
    bat_vol3 = bat_vol2;
    bat_vol2 = bat_vol1;
    bat_vol1 = get_vol;
    return get_vol;
}

static uint8_t flash_print_flag = 0;
int main(void)
{
    //for hold the SWD before sleep
    delay_n_10us(10*1000);
    NS_LOG_INIT();
    

    KeyInputExtiInit(KEY_INPUT_PORT, KEY_INPUT_PIN);
    sleep_check();

    #if  (CFG_APP_NS_IUS)
    if(CURRENT_APP_START_ADDRESS == NS_APP1_START_ADDRESS){
        NS_LOG_INFO("application 1 start new ...\r\n");
    }else if(CURRENT_APP_START_ADDRESS == NS_APP2_START_ADDRESS){
        NS_LOG_INFO("application 2 start new ...\r\n");
    }
    #endif
    app_ble_init();
    
    NS_LOG_INFO(DEMO_STRING);

    Qflash_Init();

    PB12_init();
    
    user_spi_init();     
    
    bat_vol1 = bat_vol2 = bat_vol3 = bat_vol4 = 3350;
    while (1)
    {      
        rwip_schedule();

        count_time++;

        // if(count_time < 1000000) {
            ns_iwdg_reload();
        // } else if(count_time == 1000000) {
        //     printf("iwdg test end\r\n");
        // }

        if(count_time == 600000) {
            count_time = 1;
            ADC16Bit_GetOffsetAtVCC();
            if(bat_vol1 < 3300 && bat_vol2 < 3300 && bat_vol3 < 3300 && bat_vol4 < 3300) {
                printf("bat low, go to sleep\r\n");
                press_flag = KEY_LONG_CLICKED;
                // light_on_led_num(57);
                for(int i = 8; i >= 0; i--) {
                    light_on_led_num(i);
                    delay_n_10us(100 * 1000);
                    ns_iwdg_reload();
                }
            }
        }

        if(count_press_down_time > 0) {
            if(GPIO_ReadInputDataBit(KEY_INPUT_PORT, KEY_INPUT_PIN) == RESET) {
                uint32_t abs_time = count_time - count_press_down_time;
                if (abs_time > KEY_LONG_LONG_CLICK_TIME) {
                    printf("abs_time = %d %d\r\n", abs_time, KEY_LONG_LONG_CLICK_TIME);
                    press_flag = KEY_LONG_LONG_CLICKED;
                } else if (abs_time > KEY_LONG_CLICK_TIME) {
                    press_flag = KEY_LONG_CLICKED;
                }
            } else {
                count_press_down_time = 0;
                press_flag = KEY_NORMAL;
                flash_print_flag = 0;
            }
        }

        if(press_flag == KEY_CLICKED)
        {    
            GPIO_SetBits(GPIOB, GPIO_PIN_12);

            press_flag = KEY_NORMAL;
            mov_switch();
            // change_in_mode
        } else if (press_flag == KEY_LONG_CLICKED || press_flag == KEY_LONG_LONG_CLICKED) {
            extern uint8_t strat_store_process;
            if (strat_store_process && press_flag == KEY_LONG_CLICKED) {
                if(flash_print_flag == 0) {
                    flash_print_flag = 1;
                    printf("ble save flash, do not sleep\r\n");
                }
                continue;
            } else {
                light_on_led_num(0);
                delay_n_10us(700);
                printf("going to reset\r\n");
                GPIO_ResetBits(GPIOB, GPIO_PIN_12);
                while(GPIO_ReadInputDataBit(KEY_INPUT_PORT, KEY_INPUT_PIN) == RESET);
                set_flag_reset_sleep();
                NVIC_SystemReset();

            }
        }
    }
}




//                GLOBAL_INT_DISABLE();
//                rwip_reset();
//                GPIO_ResetBits(GPIOB, GPIO_PIN_12);
//                do
//                {    
//                    ip_deepslwkup_set(0);
//                    REG32(0x40028030) |= 0x07;
//                    while(PWR->CR1&0x20); //wait ble sleep
//                    user_spi_sleep();

//                   
//                    //user_spi_sleep();
//                    RCC->CFG |=  RCC_HCLK_DIV2; //APB1 = HCLK/2, APB1 max is 32M
//                    NS_LOG_INIT();

//                    KeyInputExtiInit(KEY_INPUT_PORT, KEY_INPUT_PIN);
//            
//                    printf("wakeup\r\n");
//                }while(0);
//                GLOBAL_INT_RESTORE();
//                set_flag_powerup_by_long_press();
//                NVIC_SystemReset();




/**
 * @}
 */

